package com.cc.demo.service.impl;

import com.alibaba.fastjson.JSON;
import com.cc.demo.constant.MessageStatusEnum;
import com.cc.demo.dto.TransactionMessage;
import com.cc.demo.entity.TransactionEventMessage;
import com.cc.demo.exception.DuplicateMessageException;
import com.cc.demo.exception.TransactionEventMessageException;
import com.cc.demo.repository.TransactionEventMessageRepository;
import com.cc.demo.service.TransactionEventMessageService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Service
@RequiredArgsConstructor
public class TransactionEventMessageServiceImpl implements TransactionEventMessageService {

    private final TransactionEventMessageRepository transactionEventMessageRepository;

    private final ApplicationContext applicationContext;


    @Transactional
    @Override
    public TransactionEventMessage saveMessageWaitingConfirm(TransactionEventMessage transactionEventMessage) {
        //1. 判断message是否重复
        Optional<TransactionEventMessage> messageOptional = this.findTransactionEventMessage(transactionEventMessage);
        if (messageOptional.isEmpty()) {
            transactionEventMessage.setStatus(MessageStatusEnum.WAITING_CONFIRM.name());
            //不重复,处理流程
            return transactionEventMessageRepository.save(transactionEventMessage);
        } else {
            // 重复
            throw new DuplicateMessageException("重复消息");
        }
    }

    @Transactional
    @Override
    public void confirmAndSendMessage(Integer id) {
        Optional<TransactionEventMessage> messageOptional = this.getMessageById(id);
        if (messageOptional.isEmpty()) {
            throw new TransactionEventMessageException("找不到对应的消息");
        }
        TransactionEventMessage transactionEventMessage = messageOptional.get();
        transactionEventMessage.setStatus(MessageStatusEnum.CONFIRMED.name());
        transactionEventMessageRepository.save(transactionEventMessage);
        //发送message
        this.directSendMessage(transactionEventMessage);
    }

    @Transactional
    @Override
    public boolean saveAndSendMessage(TransactionEventMessage transactionEventMessage) {
        return false;
    }

    @Override
    public void directSendMessage(TransactionEventMessage transactionEventMessage) {
        TransactionMessage<?> transactionMessage = this.convertTransactionEventMessageToMessage(transactionEventMessage);
        ((MessageChannel) applicationContext.getBean(transactionEventMessage.getChannel())).send(MessageBuilder.withPayload(transactionMessage).build());
    }

    @Override
    public void resendMessage(TransactionEventMessage transactionEventMessage) {

    }

    @Override
    public void resendMessageById(Integer id) {

    }


    @Override
    public Optional<TransactionEventMessage> getMessageById(Integer id) {
        return transactionEventMessageRepository.findById(id);
    }

    @Override
    public void setTransactionEventMessageToCompleted(TransactionEventMessage transactionEventMessage) {
        //TODO 校验 ,id 校验，@NotNull
        setTransactionEventMessageToStatus(transactionEventMessage, MessageStatusEnum.COMPLETED.name());
        //TODO 如果找不到该如何处理
    }

    private void setTransactionEventMessageToStatus(TransactionEventMessage transactionEventMessage, String status) {
        Optional<TransactionEventMessage> transactionEventMessageOptional = transactionEventMessageRepository.findById(transactionEventMessage.getId());
        // TODO 如果已经是Completed的状态就不需要做修改了
        if (transactionEventMessageOptional.isPresent() && !StringUtils.equalsIgnoreCase(transactionEventMessageOptional.get().getStatus(), MessageStatusEnum.COMPLETED.name())) {
            TransactionEventMessage eventMessage = transactionEventMessageOptional.get();
            eventMessage.setMessageResult(transactionEventMessage.getMessageResult());
            eventMessage.setDestination(transactionEventMessage.getDestination());
            eventMessage.setDuration(transactionEventMessage.getDuration());
            eventMessage.setReceivedTime(transactionEventMessage.getReceivedTime());
            eventMessage.setExecutedTime(transactionEventMessage.getExecutedTime());
            eventMessage.setMessageNote(transactionEventMessage.getMessageNote());
            //TODO 设置更多的参数
            eventMessage.setStatus(status);
            transactionEventMessageRepository.save(eventMessage);
        }
    }

    @Override
    public void setTransactionEventMessageToFailed(TransactionEventMessage transactionEventMessage) {
        //TODO 校验 ,id 校验，@NotNull
        setTransactionEventMessageToStatus(transactionEventMessage, MessageStatusEnum.FAILED.name());
        //TODO 如果找不到该如何处理
    }


    @Override
    public Optional<TransactionEventMessage> findTransactionEventMessage(TransactionEventMessage eventMessage) {
        //TODO 校验
        String businessKey = eventMessage.getBusinessKey();
        String domain = eventMessage.getDomain();
        String owner = eventMessage.getOwner();
        return transactionEventMessageRepository.findTransactionEventMessageByBusinessKeyAndDomainAndOwner(businessKey, domain, owner);
    }

    @Override
    public TransactionEventMessage convertMessageToTransactionEventMessage(TransactionMessage<?> transactionMessage) {
        //TODO 更多的校验逻辑
        //TODO 抛出的异常如何处理
        if (Objects.isNull(transactionMessage)) {
            throw new TransactionEventMessageException("transactionMessage不允许为空");
        }
        if (Objects.isNull(transactionMessage.getChannel())) {
            throw new TransactionEventMessageException("channel不允许为空");
        }
        TransactionEventMessage transactionEventMessage = TransactionEventMessage.builder()
                .messageBody(JSON.toJSONString(transactionMessage.getBody()))
                .messageResult(transactionMessage.getMessageResult())
                .messageNote(transactionMessage.getMessageNote())
                .executedTime(transactionMessage.getExecutedTime())
                .duration(transactionMessage.getDuration())
                .destination(transactionMessage.getDestination())
                .domain(transactionMessage.getDomain())
                .businessKey(transactionMessage.getBusinessKey())
                .channel(transactionMessage.getChannel())
                .receivedTime(transactionMessage.getReceivedTime())
                .status(transactionMessage.getStatus())
                .owner(transactionMessage.getOwner()).build();
        transactionEventMessage.setId(transactionMessage.getId());
        return transactionEventMessage;
    }

    @Override
    public TransactionMessage<?> convertTransactionEventMessageToMessage(TransactionEventMessage transactionEventMessage) {
        return TransactionMessage.builder()
                .businessKey(transactionEventMessage.getBusinessKey())
                .domain(transactionEventMessage.getDomain())
                .destination(transactionEventMessage.getDestination())
                .channel(transactionEventMessage.getChannel())
                .id(transactionEventMessage.getId())
                .owner(transactionEventMessage.getOwner())
                .duration(transactionEventMessage.getDuration())
                .executedTime(transactionEventMessage.getExecutedTime())
                .messageResult(transactionEventMessage.getMessageResult())
                .messageNote(transactionEventMessage.getMessageNote())
                .receivedTime(transactionEventMessage.getReceivedTime())
                .status(transactionEventMessage.getStatus())
                .body(transactionEventMessage.getMessageBody()).build();
    }

    @Override
    public void batchSendConfirmedMessage() {
        List<TransactionEventMessage> transactionEventMessageByStatus = this.transactionEventMessageRepository.findTransactionEventMessageByStatus(MessageStatusEnum.CONFIRMED.name());
        // 确认并发送
        //TODO 可以考虑做成异步
        transactionEventMessageByStatus.forEach(this::directSendMessage);
    }
}

